package fredgolm;

public class Solver {

    private double[] args;
    private double[] f;
    private int basisDim;
    private PascalTriangle pasTriangle;


    public Solver(){};
    public Solver(double[] _args, double[] _f, int _basisDim) {
        basisDim = _basisDim;
        args = _args;
        f = _f;
        pasTriangle = new PascalTriangle(basisDim*2);
    }

   
    public double[] getCoefficents() {

        double[] A = new double[basisDim];
        double[] legandrePolynom;

        for(int i=0; i<basisDim; i++) {
            legandrePolynom = this.getLegandrePolynom(i);

            double scalar_f_l = 0;

            for(int t=0; t<args.length-1 ; t++) {
               scalar_f_l += (f[t]+f[t+1])/2*getIntegral(legandrePolynom, args[t], args[t+1]);
                 // scalar_f_l += f[t+1]*getIntegral(legandrePolynom, args[t], args[t+1]);

            }

            double scalar_l_l = getIntegral(polynomSquare(legandrePolynom), args[0], args[args.length-1]);
            
            A[i] = scalar_f_l/scalar_l_l;
        }

        return A;

    }

    public static double myPow(double a, double n) {
        /*double sign;
        sign = (a > 0 || n % 2 == 0) ? 1 : -1;
        return sign*(Math.exp((n)*Math.log(Math.abs(a))));*/
        if(a==0) return 0;
        double res = 1;
        for(int i=0; i < n; i++) {
            res*=a;
        }
        return res;
    }

    public static double getIntegral(double[] C, double a, double b) {

        double result = 0;
        double aPower = a;
        double bPower = b;

        if ( a == 0 ) {
            aPower = 0;
        }

        if ( b == 0 ) {
            bPower = 0;
        }

        for(int i=0; i<C.length; i++) {
//            result+= C[i]*(Math.pow(b, i+1) - Math.pow(a, i+1))/(i+1);
            //result+= C[i]*(myPow(b, i+1) - myPow(a, i+1))/(i+1);
            result+= C[i]*(bPower - aPower) / (i+1);
            aPower*=a;
            bPower*=b;
        }

        return result;
    }

    public static double[] polynomSquare (double[] C) {
        double[] result = new double[C.length*2-1];

        for(int i=0; i < C.length; i++) {
            result[i*2]+= C[i]*C[i];

            for(int j=i+1; j<C.length; j++) {
                result[i+j]+= C[i]*C[j]*2;
            }
        }

        return result;
    }

    public double[] getLegandrePolynom (int n) {
        double[] result = new double[n+1];

        for(int k=0; k < n/2+1; k++) {
           result[n-2*k] = (k%2 == 0 ? 1 : -1)* pasTriangle.getBinomialCoef(n, k) * pasTriangle.getBinomialCoef(2*n-2*k, n);
        }

        double denominator = 2<<n;


        for(int i=0; i<n+1; i++) {
            result[i]/=denominator;
        }

        return result;
    }

    public static double get_F(double[] coef, double point) {
        if ( point == 0 ) {
            return coef[0];
        }
        
        double res = 0;
        double x = 1;

        for(int i=0; i<coef.length; i++) {
            res += coef[i] * x;
            x*=point;
        }

        return res;
    }

   
    public double[] addPolinoms(double[] A, double[] B) {
        for(int i=0; i<A.length; i++) {
            A[i]+=B[i];
        }

        return A;
    }

    public double[] multiplyPolinomOnConst(double[]A, double c) {

        for(int i=0; i<A.length; i++) {
            A[i] = A[i]*c;
        }

        return A;
    }

     public double[] getPolinom() {
        double[] coef = this.getCoefficents();
        double[] resPolinom = new double[basisDim+1];
        double[] tmp;


        for(int i=0; i < basisDim; i++) {
            tmp = this.getLegandrePolynom(i);

            for(int k=0; k<tmp.length; k++) {
                tmp[k] = tmp[k]*coef[i];
            }

            for(int t=0; t<tmp.length; t++) {
                resPolinom[t]+=tmp[t];
            }

        }

        return resPolinom;
    }


     /* public void reflectOnUnitSection(double[] aArgs) {

        for(int i=0; i<aArgs.length; i++) {
            aArgs[i] = 2*aArgs[i]/(b-a) + (a+b)/(a-b);
        }

    }

    public void unreflectUnitSection(double[] args) {

        for(int i=0; i<args.length; i++) {
            args[i] = (a+b)/2 + args[i]*(b-a)/2;
        }

    }*/
}

      